﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Objects;
using System.Linq.Expressions;

namespace Pharmacy.Data
{
    /// <summary>
    /// Provides generic isolation between the data access and other layers.
    /// </summary>
    /// <typeparam name="T">Type of the data object.</typeparam>
    public class Repository<T> : IRepository<T> where T : class
    {
        /// <summary>
        /// Gets the reference to the lazy-loading object set.
        /// </summary>
        private readonly Lazy<IObjectSet<T>> _lazyObjectSet;
        private readonly IObjectContext _context;
        /// <summary>
        /// Initializes new instance of <see cref="Repository{T}"/> with predefined <see cref="IObjectContext"/>.
        /// </summary>
        /// <param name="context">Reference to the predfined context.</param>
        public Repository(IObjectContext context)
        {
            _lazyObjectSet = new Lazy<IObjectSet<T>>(() => { return context.CreateObjectSet<T>(); });
            _context = context;            
        }

        public Repository(IObjectContext context,MergeOption mergeOption)
        {
            _lazyObjectSet = new Lazy<IObjectSet<T>>(() => { return context.CreateObjectSet<T>(mergeOption); });
            _context = context;
        }
        /// <summary>
        /// Initializes new instance of <see cref="Repository{T}"/> with predefined <see cref="IUnitOfWork"/>.
        /// </summary>
        /// <param name="unitOfWork">Reference to the predefined unit of work.</param>
        public Repository(IUnitOfWork unitOfWork)
            : this(unitOfWork.ObjectContext)
        {
        }

        /// <summary>
        /// Gets the lazily initialized value of the current <see cref="IQueryable{T}"/> instance.
        /// </summary>
        public IQueryable<T> AsQueryable()
        {
            return _lazyObjectSet.Value;
        }

        /// <summary>
        /// Get First Object, If not found, throw exception
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public T First(Expression<Func<T, bool>> where)
        {
            return _lazyObjectSet.Value.First(where);
        }
        /// <summary>
        /// Get First Object, Null if not found
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public T FirstOrDefault(Expression<Func<T, bool>> where)
        {
            return _lazyObjectSet.Value.FirstOrDefault(where);
        }
        /// <summary>
        /// Delete Entity
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(T entity)
        {
            _lazyObjectSet.Value.DeleteObject(entity);
        }

        /// <summary>
        /// Delete Entity
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(List<T> lstEntity)
        {
            for (int i= lstEntity.Count -1; i>=0; i--)
            {
                _lazyObjectSet.Value.DeleteObject(lstEntity[i] as T);       
            }
                     
        }

        /// <summary>
        /// Add Entity
        /// </summary>
        /// <param name="entity"></param>
        public void Add(T entity)
        {
            _lazyObjectSet.Value.AddObject(entity);
        }
        /// <summary>
        /// Attach Entity
        /// </summary>
        /// <param name="entity"></param>
        public void Attach(T entity)
        {
            _lazyObjectSet.Value.Attach(entity);
        }

        public void AttachAsModify(T entity,params Expression<Func<T,object>>[] properties)
        {
            _context.AttachAsModify(entity, properties);
        }
    }

}
